package cn.turboinfo.fuyang.api.gateway.share.framework.http;

import cn.turboinfo.fuyang.api.gateway.share.constant.ShareRestConstants;
import cn.turboinfo.fuyang.api.gateway.share.framework.http.fo.ShareRestResponseFO;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;

/**
 * author: sunshow.
 */
@Slf4j
@RestControllerAdvice(basePackages = {
        "cn.turboinfo.fuyang.api.gateway.share.controller",
        "cn.turboinfo.fuyang.api.gateway.share.contract",
})
public class ShareExceptionAdvice {

    @ExceptionHandler(Throwable.class)
    public ResponseEntity<ShareRestResponseFO> exceptionHandler(Throwable e) {
        return doInExceptionHandler(e);
    }

    private static ResponseEntity<ShareRestResponseFO> doInExceptionHandler(Throwable e) {
        log.error(e.getMessage(), e);

        String message = e.getMessage();
        int code = ShareRestConstants.RC_ERROR_DEFAULT;

        if (e instanceof ShareResponseBodyWrapperException) {
            ShareResponseBodyWrapperException exception = (ShareResponseBodyWrapperException) e;
            code = exception.getCode();
            message = exception.getMessage();

            return new ResponseEntity<>(ShareRestResponseFO.error(code, message, exception.getData()), HttpStatus.INTERNAL_SERVER_ERROR);
        } else if (e instanceof MethodArgumentNotValidException) {
            BindingResult bindingResult = ((MethodArgumentNotValidException) e).getBindingResult();
            List<String> errorList = new ArrayList<>();
            bindingResult.getAllErrors().forEach(err -> errorList.add(err.getDefaultMessage()));
            message = "参数验证出错: " + StringUtils.join(errorList, "; ");
            code = ShareRestConstants.RC_ERROR_BAD_REQUEST;
            return new ResponseEntity<>(ShareRestResponseFO.error(code, message), HttpStatus.BAD_REQUEST);
        } else if (e instanceof ConstraintViolationException) {
            ConstraintViolationException constraintViolationException = (ConstraintViolationException) e;

            message = constraintViolationException.getConstraintViolations()
                    .stream()
                    .map(ConstraintViolation::getMessage)
                    .findFirst()
                    .orElse("数据格式验证错误");
            code = ShareRestConstants.RC_ERROR_BAD_REQUEST;
            return new ResponseEntity<>(ShareRestResponseFO.error(code, message), HttpStatus.BAD_REQUEST);
        }

        return new ResponseEntity<>(ShareRestResponseFO.error(code, message), HttpStatus.INTERNAL_SERVER_ERROR);
    }

    @Slf4j
    @RestControllerAdvice(basePackages = {
            "cn.turboinfo.fuyang.api.gateway.web.framework.http",
    })
    public static class ShareErrorHandler {

        @ExceptionHandler(ShareServletWrapperException.class)
        public ResponseEntity<ShareRestResponseFO> internalServletWrapperExceptionHandler(ShareServletWrapperException e) {
            return doInExceptionHandler(e.getCause());
        }

    }

}
